using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

using DevExpress.Data;
using DevExpress.XtraEditors;
using DevExpress.XtraGrid.Columns;
using DevExpress.XtraGrid.Views.Base;
using DevExpress.XtraGrid.Views.Grid;

using Microsoft.Win32;

using Verety.SharedMeta.UIMeta.Interfaces;

using Verety.SharedMeta.DirectoryServiceMeta;
using Verety.SharedMeta.DirectoryServiceMeta.Contacts;
using Verety.SharedMeta.DirectoryServiceMeta.Contacts.ColumnNames;
using Verety.SharedMeta.DirectoryServiceMeta.Enums;

using SBPweb.Localization;
using SBPweb.Modules.Modularity;
using SBPweb.Contracts;
using SBPweb.Contracts.StateManagement;
using SBPweb.Contracts.Implementation;
using System.IO;

namespace SBPweb.Modules.ContactsManager.Controls
{
	#region Public delegates

	public delegate void ExpandDelegate(object sender, RowEventArgs e);
    public delegate void ExpandAllDelegate();

	#endregion

	public partial class ContactGrid : DevExpress.XtraGrid.GridControl, IRosterGrid
    {
        #region Private members

        private bool clickOnColumn = false;
        private string lastGroupNode = string.Empty;
        private string draggingLastPlace = null;
        private DateTime draggingLastTime = DateTime.Now;

        private IDirectoryService mDirectoryService;

        public ImageList ImageList;
        private bool mUseAlphaBlending;

        private bool hideOfflineContacts = false;
        private List<int> expandedRows = new List<int>(); // list of actual expanded rows

        private List<string> selectedGroupsName = new List<string>();
        private List<string> selectedDataRowsJID = new List<string>();
        private DataTable MainViewCloneTable;
        private DataView MainDataView;
        private Timer gridRefreshTimer;

		private DevExpress.XtraGrid.Scrolling.ScrollInfo si;

		private int totalCount;
		private decimal totalSum;

		private IModule mParentModule;

		internal IDirectoryService DirectoryService
		{
			get
			{
				return mDirectoryService;
			}
			set
			{
				if (mDirectoryService != null) return;

				mDirectoryService = value;

				DirectoryService.Contacts.OnContactListRefreshBegin += new Verety.SharedMeta.MessagingServiceMeta.Contacts.ContactListRefreshEndHandler(Contacts_OnContactListRefreshBegin);
				DirectoryService.Contacts.OnContactListRefreshEnd += new Verety.SharedMeta.MessagingServiceMeta.Contacts.ContactListRefreshEndHandler(Contacts_OnContactListRefreshEnd);
				DirectoryService.Connection.OnDisconnect += new Verety.SharedMeta.MessagingServiceMeta.Connection.ConnectionHandler(Connection_OnDisconnect);
				DirectoryService.Connection.OnAuthenticate += new Verety.SharedMeta.MessagingServiceMeta.Connection.ConnectionHandler(Connection_OnAuthenticate);


				if (DirectoryService.Contacts.FirstRosterArrived)
				{
					this.RefreshDataSource();
					gridRefreshTimer.Start();
				}
			}
		}

		private IStateManagementService StateManagementService
		{
			get
			{
				if (mParentModule == null)
				{
					return null;
				}
				return mParentModule.Services[typeof(IStateManagementService)] as IStateManagementService;
			}
		}

        #endregion

        #region Public properties

        public string[] Groups
        {
            get
            {
                List<string> retValL = new List<string>();
                DataRowCollection rows = (DirectoryService.Contacts as IDirectoryContactsManager).GroupsTable.Rows;
                foreach (DirectoryContactsDataset.GroupsRow gRow in rows)
                {
                    if (!retValL.Contains(gRow.GroupName) && gRow.Shared == false)
                    {
                        retValL.Add(gRow.GroupName);
                    }
                }
                return retValL.ToArray();
            }
        }

        public DataRow[] SelectedRows
        {
            get
            {
                DevExpress.XtraGrid.Views.Grid.GridView gv = MainView as DevExpress.XtraGrid.Views.Grid.GridView;

                if (gv == null)
                {
                    return new DataRow[0];
                }

                if (gv.SelectedRowsCount > 0)
                {
                    int[] selectedRows = gv.GetSelectedRows();
                    List<DataRow> retList = new List<DataRow>();
                    foreach (int sr in selectedRows)
                    {
                        bool group = gv.IsGroupRow(sr);
                        System.Data.DataRowView drv = (gv.GetRow(sr) as System.Data.DataRowView);
                        if (drv != null)
                        {
                            DataRow retVal = (drv.Row as DataRow);

                            if (group)
                            {
                                DataRow tempRow = (retVal.Table as DataTable).NewRow();
                                tempRow["GroupName"] = retVal["GroupName"];
                                retList.Add(tempRow);
                            }
                            else
                            {
                                retList.Add(retVal);
                            }
                        }
                    }
                    return retList.ToArray();
                }
                return new DataRow[0];
            }
        }

        public new GridView MainView
        {
            get
            {
                return base.MainView as GridView;
            }
            set
            {
                base.MainView = value;
            }
        }

        public bool UseAlphaBlending
        {
            get
            {
                return mUseAlphaBlending;
            }
            set
            {
                if (mUseAlphaBlending = value)
                {
                    this.ImageList = il32b;
                }
                else
                {
                    this.ImageList = il8b;
                }
            }
        }

        public bool HideOfflineContacts
        {
            get
            {
                return hideOfflineContacts;
            }
            set
            {
                hideOfflineContacts = value;

                if (hideOfflineContacts)
                {
                    if (this.gridView1.GroupSummary.Count > 1)
                    {
                        this.gridView1.GroupSummary.Clear();
                        this.gridView1.GroupSummary.AddRange(
                            new DevExpress.XtraGrid.GridSummaryItem[]
								{
									new DevExpress.XtraGrid.GridGroupSummaryItem(DevExpress.Data.SummaryItemType.Count, "JID", null, "(" + LocalizationExtender.GetString(this, "RosterGridGroupSummaryAll") + ")"),
								}
                        );
                    }
                }
                else
                {
                    if (this.gridView1.GroupSummary.Count < 2)
                    {
                        this.gridView1.GroupSummary.Clear();
                        this.gridView1.GroupSummary.AddRange(
                            new DevExpress.XtraGrid.GridSummaryItem[]
								{
									new DevExpress.XtraGrid.GridGroupSummaryItem(DevExpress.Data.SummaryItemType.Count, "JID", null, "(" + LocalizationExtender.GetString(this, "RosterGridGroupSummaryAll")),
									new DevExpress.XtraGrid.GridGroupSummaryItem(DevExpress.Data.SummaryItemType.Custom, "Availability", null, LocalizationExtender.GetString(this, "RosterGridGroupSummaryAvailable") + ")")
								}
                        );
                    }
                }

                this.RefreshDataSource();
            }
        }

        public bool ToggleHideOfflineContacts()
        {
            HideOfflineContacts = !HideOfflineContacts;
            ExpandRows();
            return HideOfflineContacts;
        }

        public List<string> GroupsInRoster
        {
            get
            {
                List<string> groups = new List<string>();

                DataRowCollection gr = (MainView.DataSource as DataView).Table.Rows;

                foreach (DataRow g in gr)
                {
                        string groupName = g["GroupName"].ToString();
                        if (!groups.Contains(groupName))
                        {
                            groups.Add(groupName);
                        }
                }

                return groups;
            }
        }

        public int SelectedRowHandle
        {
            get
            {
                DevExpress.XtraGrid.Views.Grid.GridView gv = this.MainView as DevExpress.XtraGrid.Views.Grid.GridView;

                if (gv.SelectedRowsCount > 0)
                {
                    int[] selectedRows = gv.GetSelectedRows();
                    return selectedRows[0];
                }
                else
                {
                    return int.MinValue;
                }
            }
            set
            {
                DevExpress.XtraGrid.Views.Grid.GridView gv = this.MainView as DevExpress.XtraGrid.Views.Grid.GridView;

                try
                {
                    if (value != Int32.MinValue)
                    {
                        gv.FocusedRowHandle = value;
                    }
                }
                catch (Exception ex)
                {
                    ContactsManagerModule.LogManager.WriteError(this, string.Format("Cannot set selected row handle.\n{0}", ex.Message), "ContactManager");
                }
            }
        }

        public List<int> ExpandedRows
        {
            get
            {
                return this.expandedRows;
            }
            set
            {
                this.expandedRows = value;
                ExpandRows();
            }
        }
        
        #endregion

        public event SelectionChangedEventHandler SelectionChanged
        {
            add
            {
                this.MainView.SelectionChanged += value;
            }
            remove
            {
                try
                {
					if (MainView != null)
					{
						this.MainView.SelectionChanged -= value;
					}
                }
                catch { }
            }
		}

		//Nobody raises... :S 
		public event RosterGridSelectionChangedHandler OnRosterGridSelectionChanged;

		#region Constructor logic

		public ContactGrid(IModule parentModule)
        {
            try
            {
				mParentModule = parentModule;

                this.SetStyle(ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.SupportsTransparentBackColor, true);

                InitializeComponent();
                this.UseAlphaBlending = true;

                this.MainView.RowHeight = 26;
                this.MainView.OptionsView.ShowHorzLines = false;
                this.MainView.OptionsView.ShowVertLines = false;
                this.MainView.OptionsView.ShowFilterPanelMode = ShowFilterPanelMode.Default;
                this.MainView.OptionsView.ColumnAutoWidth = true;
                this.MainView.OptionsSelection.MultiSelect = true;
				((DevExpress.XtraGrid.Views.Base.ColumnView)(MainView)).Columns["colIcon"].OptionsColumn.AllowMove = false;
				((DevExpress.XtraGrid.Views.Base.ColumnView)(MainView)).Columns["colIcon"].OptionsColumn.AllowGroup = DevExpress.Utils.DefaultBoolean.False;

                this.si = GetScrollInfo();

                colNickName.SortOrder = ColumnSortOrder.Ascending;

                this.MainView.GroupRowCollapsed += new RowEventHandler(MainView_GroupRowCollapsed);
                this.MainView.GroupRowExpanded += new RowEventHandler(MainView_GroupRowExpanded);
                this.MainView.EndGrouping += new EventHandler(MainView_EndGrouping);
                this.MainView.CustomDrawCell += new RowCellCustomDrawEventHandler(MainView_CustomDrawCell);
                this.MainView.CustomSummaryCalculate += new CustomSummaryEventHandler(MainView_CustomSummaryCalculate);
                this.MainView.CustomRowFilter += new RowFilterEventHandler(MainView_CustomRowFilter);
                this.MouseDown += new MouseEventHandler(RosterGrid_MouseDown);
                this.MouseMove += new MouseEventHandler(RosterGrid_MouseMove);
                this.DragOver += new DragEventHandler(RosterGrid_DragOver);
                this.DragDrop += new DragEventHandler(RosterGrid_DragDrop);

                gridRefreshTimer = new Timer();
                gridRefreshTimer.Tick += new EventHandler(gridRefreshTimer_Tick);
                gridRefreshTimer.Interval = 1000;
                this.components.Add(gridRefreshTimer);

                Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
                
                LocalizationExtender.OnInvalidatingControls += new EventHandler(LocalizationExtender_OnInvalidatingControls);

                //DirectoryService = directoryService;
                
				LookAndFeel.ActiveLookAndFeel.UseWindowsXPTheme = true;
				LookAndFeel.ActiveLookAndFeel.Style = DevExpress.LookAndFeel.LookAndFeelStyle.Flat;

                if (OnRosterGridSelectionChanged != null){}
            
            }
            catch (Exception ex)
            {
                ContactsManagerModule.LogManager.WriteError(this, "Rostergrid initialization failed. " + ex.Message, "ContactManager");
            }
		}

		#endregion

		#region Event handlers

		private void Application_ApplicationExit(object sender, EventArgs e)
        {
            if (gridRefreshTimer != null)
            {
                gridRefreshTimer.Stop();
            }
        }

        private void gridRefreshTimer_Tick(object sender, EventArgs e)
        {
            ReBindDataSource();
		}

		private void Connection_OnAuthenticate(object sender)
		{
			if (this.InvokeRequired)
			{
				this.Invoke(new Verety.SharedMeta.MessagingServiceMeta.Connection.ConnectionHandler(Connection_OnAuthenticate), sender);
				return;
			}

			gridRefreshTimer.Start();
		}

		private void Connection_OnDisconnect(object sender)
		{
			gridRefreshTimer.Stop();
			DirectoryService.Contacts.OnContactListRefreshBegin -= new Verety.SharedMeta.MessagingServiceMeta.Contacts.ContactListRefreshEndHandler(Contacts_OnContactListRefreshBegin);
			DirectoryService.Contacts.OnContactListRefreshEnd -= new Verety.SharedMeta.MessagingServiceMeta.Contacts.ContactListRefreshEndHandler(Contacts_OnContactListRefreshEnd);
			DirectoryService.Connection.OnDisconnect -= new Verety.SharedMeta.MessagingServiceMeta.Connection.ConnectionHandler(Connection_OnDisconnect);
		}

		private void Contacts_OnContactListRefreshBegin(object sender)
		{
			if (InvokeRequired)
			{
				this.Invoke(new SenderHandler(Contacts_OnContactListRefreshBegin), sender);
				return;
			}

			gridRefreshTimer.Stop();
		}

		private void Contacts_OnContactListRefreshEnd(object sender)
		{
			if (InvokeRequired)
			{
				this.Invoke(new SenderHandler(Contacts_OnContactListRefreshEnd), sender);
				return;
			}

			ExpandRows();

			gridRefreshTimer.Start();
		}

		private void MainView_CustomSummaryCalculate(object sender, CustomSummaryEventArgs e)
		{
			DevExpress.XtraGrid.GridSummaryItem gsItem = e.Item as DevExpress.XtraGrid.GridSummaryItem;
			GridView view = sender as GridView;

			switch (e.SummaryProcess)
			{
				case CustomSummaryProcess.Start:
					InitStartValue();
					break;
				case CustomSummaryProcess.Calculate:
					if (e.FieldValue != null && e.FieldValue.ToString() == "available")
					{
						if (e.IsGroupSummary) totalCount++;
					}
					if (e.IsTotalSummary) totalSum++;
					break;
				case CustomSummaryProcess.Finalize:
					if (e.IsGroupSummary)
						e.TotalValue = totalCount;
					if (e.IsTotalSummary)
						e.TotalValue = totalSum;
					break;
			}
		}

		private void LocalizationExtender_OnInvalidatingControls(object sender, EventArgs e)
		{
			if (this.gridView1.GroupSummary.Count == 1)
			{
				this.gridView1.GroupSummary.Clear();
				this.gridView1.GroupSummary.AddRange(
					new DevExpress.XtraGrid.GridSummaryItem[]
						{
							new DevExpress.XtraGrid.GridGroupSummaryItem(DevExpress.Data.SummaryItemType.Count, "JID", null, "(" + LocalizationExtender.GetString(this, "RosterGridGroupSummaryAll") + ")"),
						}
				);
			}
			else if (this.gridView1.GroupSummary.Count == 2)
			{
				this.gridView1.GroupSummary.Clear();
				this.gridView1.GroupSummary.AddRange(
					new DevExpress.XtraGrid.GridSummaryItem[]
								{
									new DevExpress.XtraGrid.GridGroupSummaryItem(DevExpress.Data.SummaryItemType.Count, "JID", null, "(" + LocalizationExtender.GetString(this, "RosterGridGroupSummaryAll")),
									new DevExpress.XtraGrid.GridGroupSummaryItem(DevExpress.Data.SummaryItemType.Custom, "Availability", null, LocalizationExtender.GetString(this, "RosterGridGroupSummaryAvailable") + ")")
								}
				);
			}
		}

		#region Drag&Drop

		private void RosterGrid_MouseDown(object sender, MouseEventArgs e)
		{
			DataRow mr = this.GetNodeAt((new Point(e.X, e.Y)));
			DevExpress.XtraGrid.Views.Grid.ViewInfo.GridHitInfo hi = this.MainView.CalcHitInfo(new Point(e.X, e.Y));

			clickOnColumn = !hi.InRowCell;

			if (mr != null)
			{
				if (mr["JID"].ToString() == string.Empty)
				{
					return;
				}
				lastGroupNode = mr["GroupName"].ToString();
			}
		}

		private void RosterGrid_MouseMove(object sender, MouseEventArgs e)
		{
			if (e.Button == MouseButtons.Left)
			{
				DevExpress.XtraGrid.Views.Grid.ViewInfo.GridHitInfo hi = this.MainView.CalcHitInfo(new Point(e.X, e.Y));

				if (!hi.InRow || clickOnColumn)
				{
					return;
				}

				bool first = true;
				string droppingValues = string.Empty;
				foreach (DataRow mr in this.SelectedRows)
				{
					if (mr != null)
					{
						string groupName = mr["GroupName"].ToString();

						if (mr["JID"].ToString() == string.Empty)
							continue;
						else
						{
							int statusTime = 0;
							if (mr["StatusTime"].ToString().Length > 0)
							{
								try
								{
									statusTime = Convert.ToInt32(mr["StatusTime"]);
								}
								catch //(Exception ex)
								{
									statusTime = 0;
								}
							}
							string statustime = string.Empty;
							if (statusTime > (60 * 60 * 24))
							{
								statustime = string.Format("{0} {1}", ((int)(statusTime / (60 * 60 * 24))).ToString(), LocalizationExtender.GetString(this, "RosterGridSummaryDay"));
								statusTime = statusTime % (60 * 60 * 24);
							}
							if (statusTime > (60 * 60))
							{
								if (statustime.Length > 0)
								{
									statustime = string.Format("{0} ", statustime);
								}
								statustime = string.Format("{0}{1} {2}", statustime, ((int)(statusTime / (60 * 60))).ToString(), LocalizationExtender.GetString(this, "RosterGridSummaryHour"));
								statusTime = statusTime % (60 * 60);
							}
							if (statusTime > 60)
							{
								if (statustime.Length > 0)
								{
									statustime = string.Format("{0} ", statustime);
								}
								statustime = string.Format("{0}{1} {2}", statustime, ((int)(statusTime / 60)).ToString(), LocalizationExtender.GetString(this, "RosterGridSummaryMin"));
								statusTime = statusTime % 60;
							}
							if (statustime.Length > 0)
							{
								statustime = string.Format("{0} ", statustime);
							}
							statustime = string.Format("{0}{1} {2}", statustime, statusTime.ToString(), LocalizationExtender.GetString(this, "RosterGridSummarySec"));
							string status = string.Format("{0} {1}", mr["Status"].ToString(), mr["Message"].ToString()).Trim();
							if (status.Length == 0)
							{
								status = DirectoryStatusNames.Unknown;
							}

							statustime = string.Format(LocalizationExtender.GetString("RosterGridSummaryInStatus"), status, statustime);
							if (!first)
								droppingValues = droppingValues + Environment.NewLine + Environment.NewLine;
							else
								first = false;
							string jid = mr["JID"].ToString();
							if (mr["Resource"].ToString() != StringConstants.Resources.UnknownResource)
							{
								jid = string.Format("{0}/{1}", jid, mr["Resource"].ToString());
							}
							droppingValues += string.Format(LocalizationExtender.GetString("RosterGridDragAndDropText"), jid, Environment.NewLine, DateTime.Now.ToString("yyyy-MM-dd ") + System.DateTime.Now.ToShortTimeString(), groupName, mr["Resource"].ToString(), status, statustime);
						}
					}
				}
				this.DoDragDrop(droppingValues, DragDropEffects.Move | DragDropEffects.Copy);
			}
		}

		private void RosterGrid_DragOver(object sender, DragEventArgs e)
		{
			DevExpress.XtraGrid.Views.Grid.ViewInfo.GridHitInfo hi = this.MainView.CalcHitInfo(this.PointToClient(new Point(e.X, e.Y)));
			DataRow mr = this.GetNodeAt(this.PointToClient(new Point(e.X, e.Y)));

			if (hi.InRow && mr != null && e.Data.GetDataPresent(typeof(string)))
			{
				if (e.KeyState == (Convert.ToInt32(Keys.Control) & e.KeyState))
				{
					e.Effect = DragDropEffects.Copy;
				}
				else
				{
					e.Effect = DragDropEffects.Move;
				}

				DevExpress.XtraGrid.Views.Grid.GridView gv = this.MainView as DevExpress.XtraGrid.Views.Grid.GridView;

				if (gv.IsValidRowHandle(gv.GetParentRowHandle(hi.RowHandle)))
				{
					this.SelectedRowHandle = gv.GetParentRowHandle(hi.RowHandle);
				}
				else
				{
					this.SelectedRowHandle = hi.RowHandle;
				}

				if (draggingLastPlace != mr["GroupName"].ToString())
				{
					draggingLastPlace = mr["GroupName"].ToString();
					draggingLastTime = DateTime.Now;
				}
				else
				{
					TimeSpan diff = DateTime.Now - draggingLastTime;
					if (diff.TotalMilliseconds > 1000)
					{
						this.Expand(hi.RowHandle);
					}
				}

				if (DirectoryService.Contacts.IsSharedRosterGroup(mr["GroupName"].ToString())
					||
					mr["GroupName"].ToString() == StringConstants.UnfiledGroupName)
				{
					e.Effect = DragDropEffects.None;
				}
			}
			else
			{
				e.Effect = DragDropEffects.None;
			}
		}

		private void RosterGrid_DragDrop(object sender, DragEventArgs e)
		{
			DevExpress.XtraGrid.Views.Grid.ViewInfo.GridHitInfo hi = this.MainView.CalcHitInfo(this.PointToClient(new Point(e.X, e.Y)));

			DataRow mr = this.GetNodeAt(this.PointToClient((new Point(e.X, e.Y))));

			if (mr == null)
			{
				return;
			}

			if (mr["GroupName"].ToString() == lastGroupNode)
			{
				return;
			}

			if ((e.Data.GetData(DataFormats.StringFormat) as string).Contains("@")) //JID
			{
				string droppedJid = e.Data.GetData(DataFormats.StringFormat) as string;
				droppedJid = droppedJid.Split("\r".ToCharArray())[0];
				droppedJid = droppedJid.Split(" ".ToCharArray())[0];
				droppedJid = droppedJid.Split("/".ToCharArray())[0];

				if (DirectoryService.Contacts.IsSharedRosterGroup(mr["GroupName"].ToString())
					|| mr["GroupName"].ToString() == StringConstants.UnfiledGroupName
					|| mr["GroupName"].ToString() == String.Empty)
				{
					//Don't drop user to a SRG or the "Unfiled" group.
					return;
				}
				else
				{
					if ((e.KeyState != (Convert.ToInt32(Keys.Control) & e.KeyState)) || DirectoryService.Contacts.IsSharedRosterGroup((lastGroupNode)))
					{
						//Copy contact to an other group
						List<string> group = new List<string>();
						group.Add(mr["GroupName"].ToString());
						DirectoryService.Contacts.AddContact(droppedJid, DirectoryService.Contacts.GetNickName(droppedJid), group, true);
					}
					else
					{
						//Move contact to an other group
						DirectoryService.Contacts.MoveContactToGroup(droppedJid, mr["GroupName"].ToString(), lastGroupNode);
					}
					(DirectoryService.Contacts as IDirectoryContactsManager).GetContactList(droppedJid);
				}
			}
			else //Group
			{
				int currentOrderNo = 0;
				Dictionary<int, string> groupOrders = new Dictionary<int, string>();
				int newOrderNo = 0;
				int maxOrderNo = -1;

				foreach (DataRow dr in (this.DataSource as DataView).Table.Rows)
				{
					int orderNo = Convert.ToInt32(dr["GroupOrderNo"]);
					string groupName = dr["GroupName"].ToString();
					string oldGroupName = e.Data.GetData(DataFormats.StringFormat).ToString();

					if (!groupOrders.ContainsKey(orderNo))
					{
						groupOrders.Add(orderNo, groupName);
						if (orderNo > maxOrderNo)
						{
							maxOrderNo = orderNo;
						}
						if (mr["GroupName"].ToString() == groupName)
						{
							newOrderNo = orderNo;
						}
						if (oldGroupName == groupName)
						{
							currentOrderNo = orderNo;
						}
					}
				}

				if (currentOrderNo == newOrderNo)
				{
					return;
				}

				if (currentOrderNo < newOrderNo)
				{
					for (int i = currentOrderNo + 1; i <= newOrderNo; i++)
					{
						if (groupOrders.ContainsKey(i))
						{
							DirectoryService.Contacts.SetGroupOrderNo(groupOrders[i], i - 1);
						}
					}
					DirectoryService.Contacts.SetGroupOrderNo(groupOrders[currentOrderNo], newOrderNo);

					// ExpandList modifications
					int curPos = -currentOrderNo - 1;
					int newPos = -newOrderNo - 1;
					int maxPos = -maxOrderNo - 1;
					List<int> newList = new List<int>();
					for (int i = -1; i > curPos; i--)
						if (ExpandedRows.Contains(i)) newList.Add(i);
					if (ExpandedRows.Contains(curPos)) newList.Add(newPos);
					for (int i = curPos - 1; i >= newPos; i--)
						if (ExpandedRows.Contains(i)) newList.Add(i + 1);
					for (int i = newPos - 1; i >= maxPos; i--)
						if (ExpandedRows.Contains(i)) newList.Add(i);
					ExpandedRows = newList;
				}
				else
				{
					for (int i = newOrderNo; i < currentOrderNo; i++)
					{
						if (groupOrders.ContainsKey(i))
						{
							DirectoryService.Contacts.SetGroupOrderNo(groupOrders[i], i + 1);
						}
					}
					DirectoryService.Contacts.SetGroupOrderNo(groupOrders[currentOrderNo], newOrderNo);

					// ExpandList modifications
					int curPos = -currentOrderNo - 1;
					int newPos = -newOrderNo - 1;
					int maxPos = -maxOrderNo - 1;
					List<int> newList = new List<int>();
					for (int i = -1; i > newPos; i--)
						if (ExpandedRows.Contains(i)) newList.Add(i);
					for (int i = newPos; i > curPos; i--)
						if (ExpandedRows.Contains(i)) newList.Add(i - 1);
					if (ExpandedRows.Contains(curPos)) newList.Add(newPos);
					for (int i = curPos - 1; i >= maxPos; i--)
						if (ExpandedRows.Contains(i)) newList.Add(i);
					ExpandedRows = newList;
				}

				ExpandRows();
			}
		}

		#endregion

		#region Expand/Collapse Rows handleing

		private void MainView_GroupRowExpanded(object sender, RowEventArgs e)
		{
			if (this.InvokeRequired)
			{
				this.Invoke(new ExpandDelegate(MainView_GroupRowExpanded), new object[] { sender, e });
				return;
			}
			if (!this.expandedRows.Contains(e.RowHandle) && (e.RowHandle != int.MinValue))
			{
				this.expandedRows.Add(e.RowHandle);
			}
		}

		private void MainView_GroupRowCollapsed(object sender, RowEventArgs e)
		{
			if (this.expandedRows.Contains(e.RowHandle))
			{
				this.expandedRows.Remove(e.RowHandle);
			}
		}

		#endregion

		#region UI event handlers

		private void MainView_CustomDrawCell(object sender, RowCellCustomDrawEventArgs e)
		{
			switch (e.Column.Name)
			{
				case "colIcon":
					{
						GridView view = sender as GridView;
						DataRow dr = view.GetDataRow(e.RowHandle);

						if (dr == null || dr.RowState == DataRowState.Deleted || dr.RowState == DataRowState.Detached)
						{
							//TODO: Need to find solution for thread-safe usage
							return;
						}

						string availability = dr[MainViewTableColumnNames.Availability] as string;
						string status = dr[MainViewTableColumnNames.Status] as string;
						string message = dr[MainViewTableColumnNames.Message] as string;
						e.Column.MinWidth = e.Column.Width = 26;

						if (StateManagementService != null)
						{
							State state;

							if (availability != "available")
							{
								state = StateManagementService.GetStateByDirectoryName(availability);
							}
							else
							{
								state = StateManagementService.GetStateByDirectoryName(status);
							}

							if (state != null && state.Icon != null)
							{
								e.Graphics.DrawIcon(state.Icon, new Rectangle(e.Bounds.Left, e.Bounds.Top, 24, 24));
							}
						}
					}
					break;
			}
		}

		private void MainView_CustomRowFilter(object sender, RowFilterEventArgs e)
		{
			GridView view = sender as GridView;
			DataView dv = view.DataSource as DataView;

			DataRowView drv = null;
			string resource = null;
			string groupName = null;
			string userName = null;

			try
			{
				drv = dv[e.ListSourceRow];

				resource = drv["Resource"].ToString();
				groupName = drv["GroupName"].ToString();
				userName = drv["JID"].ToString();
			}
			catch (NullReferenceException) { }
			catch (Exception ex)
			{
				ContactsManagerModule.LogManager.WriteVerbose(this, string.Format("Error during mainview custom row filter.\n{0}", ex.Message), "ContactManager");
			}


			if (resource == StringConstants.Resources.UnknownResource && HideOfflineContacts)
			{
				e.Visible = false;
				e.Handled = true;
			}
			else
			{
				e.Visible = true;

				if (userName == string.Format("{0}@{1}", DirectoryService.Connection.UserName, DirectoryService.Connection.Server) && (resource == StringConstants.Resources.UnknownResource || resource == DirectoryService.Connection.Resource))
				{
					e.Visible = false;
					e.Handled = true;
				}
			}
		}

		private void MainView_EndGrouping(object sender, EventArgs e)
		{
			if (this.MainView.GetSelectedRows() != null)
			{
				int parentRowHandle;

				foreach (int handle in this.MainView.GetSelectedRows())
				{
					parentRowHandle = this.MainView.GetParentRowHandle(handle);
					if (!this.expandedRows.Contains(parentRowHandle) && (parentRowHandle != int.MinValue))
					{
						this.expandedRows.Add(parentRowHandle);
					}
				}
			}
			else
			{
				this.expandedRows.Clear();
			}

			MainView.FocusedRowHandle = -1;
		}

		#endregion

		#region Refresh

		private void ReBindDataSource()
		{
            if (DirectoryService == null) return;

			try
			{
				lock ((DirectoryService.Contacts.DataSet as DirectoryContactsDataset).SyncRoot)
				{
					int focusedRow = this.MainView.FocusedRowHandle;
					int[] selectedRows = this.MainView.GetSelectedRows();
					GridColumn focusedColumn = this.MainView.FocusedColumn;

					int scrollPos = si.VScrollPosition;

					this.MainViewCloneTable = (DirectoryService.Contacts.DataSet as DirectoryContactsDataset).MainView.Copy();
					this.MainDataView = new DataView(MainViewCloneTable);
					this.DataSource = MainDataView;

					if (focusedRow < MainViewCloneTable.Rows.Count)
					{
						foreach (int j in this.MainView.GetSelectedRows())
							this.MainView.UnselectRow(j);

						foreach (int i in selectedRows)
							this.MainView.SelectRow(i);

						this.MainView.FocusedRowHandle = focusedRow;
						this.MainView.FocusedColumn = focusedColumn;

						si.VScroll.Value = scrollPos;
					}
				}
			}
			catch (Exception e)
			{
				if (this.Disposing || this.IsDisposed)
				{
					ContactsManagerModule.LogManager.WriteWarning("ReBindDataSource() was called during disposing and it caused an exception.", "Verety.RosterViewer", "ContactManager");
				}
				else
				{
					ContactsManagerModule.LogManager.WriteError(string.Format("ReBindDataSource() caused an exception: {0}", e.Message), "Verety.RosterViewer", "ContactManager");
				}
			}
		}

		private DevExpress.XtraGrid.Scrolling.ScrollInfo GetScrollInfo()
		{
			GridView gv = (this.MainView as GridView);
			Type type = gv.GetType();
			System.Reflection.PropertyInfo pi = type.GetProperty("ScrollInfo", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
			DevExpress.XtraGrid.Scrolling.ScrollInfo si = (pi.GetValue((this.MainView as ColumnView), null) as DevExpress.XtraGrid.Scrolling.ScrollInfo);

			return si;
		}

		#endregion

		#endregion

        #region Persistency

		//private string SaveExpandedRows()
		//{
		//    string es = string.Empty;
		//    foreach (int no in ExpandedRows)
		//        es += "," + no.ToString();
		//    if (es.Length > 0) es = es.Substring(1);
		//    return es;
		//}

		//private void LoadExpandedRows(Microsoft.Win32.RegistryKey PersistenceKey)
		//{
		//    string[] s = ((string)PersistenceKey.GetValue("ExpandedRows", string.Empty)).Split(',');
		//    mExpandedRowsFromPersistency = new int[s.Length];
		//    for (int i = 0; i < s.Length; i++)
		//    {
		//        try
		//        {
		//            mExpandedRowsFromPersistency[i] = Convert.ToInt32(s[i]);
		//        }
		//        catch (Exception ex)
		//        {
		//            ContactsManagerModule.LogManager.WriteError(this, string.Format("Error during load expanded rows.\n{0}", ex.Message), "ContactManager");
		//            mExpandedRowsFromPersistency[i] = Int32.MinValue;
		//        }
		//    }
		//}

		//private void SaveGroupingColumns(Microsoft.Win32.RegistryKey PersistenceKey)
		//{
		//    int index = 0;
		//    foreach (object o in this.MainView.GroupedColumns)
		//    {
		//        index++;
		//        GridColumn gc = o as GridColumn;
		//        Microsoft.Win32.RegistryKey regKey = PersistenceKey.CreateSubKey("col_" + index);
		//        regKey.SetValue("Name", gc.Name, RegistryValueKind.String);
		//        regKey.SetValue("GroupIndex", gc.GroupIndex, RegistryValueKind.DWord);
		//        regKey.SetValue("SortOrder", gc.SortOrder.ToString(), RegistryValueKind.String);
		//    }
		//}

		//private void LoadGroupingColumns(Microsoft.Win32.RegistryKey PersistenceKey, int numberOfGroupedColumns)
		//{
		//    for (int i = 0; i < numberOfGroupedColumns; i++)
		//    {
		//        Microsoft.Win32.RegistryKey regKey = PersistenceKey.OpenSubKey("col_" + (i + 1));
		//        string colName = regKey.GetValue("Name").ToString();
		//        int groupIndex = (int)regKey.GetValue("GroupIndex");
		//        GridColumn gc = this.MainView.Columns[colName.Substring(3)];

		//        // set grouping column 
		//        gc.GroupIndex = groupIndex;

		//        //set sort info
		//        string sortInfo = regKey.GetValue("SortOrder").ToString();
		//        switch (sortInfo)
		//        {
		//            case "Ascending": gc.SortOrder = ColumnSortOrder.Ascending;
		//                break;
		//            case "Descending": gc.SortOrder = ColumnSortOrder.Descending;
		//                break;
		//            case "None": gc.SortOrder = ColumnSortOrder.None;
		//                break;
		//        }
		//    }
		//}

		//public void SaveOptionsToRegistry(Microsoft.Win32.RegistryKey PersistenceKey)
		//{
		//    PersistenceKey.SetValue("HideOfflineContacts", HideOfflineContacts ? (UInt32)1 : (UInt32)0, RegistryValueKind.DWord);
		//    PersistenceKey.SetValue("GroupedColumnNumber", this.MainView.GroupedColumns.Count, RegistryValueKind.DWord);

		//    string es = SaveExpandedRows();
		//    PersistenceKey.SetValue("ExpandedRows", es, RegistryValueKind.String);

		//    Microsoft.Win32.RegistryKey regKey = PersistenceKey.CreateSubKey("GroupingColumns");
		//    SaveGroupingColumns(regKey);
		//}

		//public void RestoreOptionsFromRegistry(Microsoft.Win32.RegistryKey PersistenceKey)
		//{

		//    HideOfflineContacts = (int)PersistenceKey.GetValue("HideOfflineContacts", (int)0) != 0;

		//    LoadExpandedRows(PersistenceKey);

		//    int numberOfGroupedColumns = (int)PersistenceKey.GetValue("GroupedColumnNumber");
		//    Microsoft.Win32.RegistryKey regKey = PersistenceKey.OpenSubKey("GroupingColumns");
		//    LoadGroupingColumns(regKey, numberOfGroupedColumns);
		//}

        #endregion

		#region Public methods

		public DataRow GetRowFromHandle(int rowHandle)
		{
			DevExpress.XtraGrid.Views.Grid.GridView gv = this.MainView as DevExpress.XtraGrid.Views.Grid.GridView;

			if (gv.GetRow(rowHandle) == null)
			{
				return null;
			}

			DataRow row = ((gv.GetRow(rowHandle) as System.Data.DataRowView).Row as DataRow);

			return row;
		}

		public DataRow GetNodeAt(Point point)
		{
			try
			{
				DevExpress.XtraGrid.Views.Grid.ViewInfo.GridHitInfo hi = this.MainView.CalcHitInfo(point);
				DevExpress.XtraGrid.Views.Grid.GridView gv = this.MainView as DevExpress.XtraGrid.Views.Grid.GridView;

				DataRow row = GetRowFromHandle(hi.RowHandle);

				if (row == null)
				{
					return null;
				}

				string groupName = row["GroupName"].ToString();

				DataRow tempRow = (DirectoryService.Contacts.DataSet as DirectoryContactsDataset).MainView.NewRow();

				if (!gv.IsGroupRow(hi.RowHandle))
				{
					tempRow["JID"] = row["JID"];
					tempRow["Availability"] = row["Availability"];
					tempRow["Resource"] = row["Resource"];
					tempRow["GroupOrderNo"] = row["GroupOrderNo"];
					tempRow["Status"] = row["Status"];
					tempRow["StatusTime"] = row["StatusTime"];
					tempRow["NickName"] = row["NickName"];
					tempRow["Message"] = row["Message"];
				}
				tempRow["GroupName"] = groupName;

				return tempRow;
			}
			catch (Exception ex)
			{
				ContactsManagerModule.LogManager.WriteInfo(this, string.Format("Error during get node on rostergrid.\n{0}", ex.Message), "ContactManager");
				return null;
			}
		}

		public void SuspendRefresh()
		{
			gridRefreshTimer.Stop();
		}

		public void ResumeRefresh()
		{
			gridRefreshTimer.Start();
		}

		#region Expand/Collapse

		//public void Expand()
		//{
		//    DevExpress.XtraGrid.Views.Grid.GridView gv = this.MainView as DevExpress.XtraGrid.Views.Grid.GridView;

		//    gv.ExpandAllGroups();
		//}

		public void Expand(int rowHandle)
		{
			DevExpress.XtraGrid.Views.Grid.GridView gv = this.MainView as DevExpress.XtraGrid.Views.Grid.GridView;

			if (rowHandle != Int32.MinValue)
				gv.ExpandGroupRow(rowHandle);
		}

		//public void Collapse()
		//{
		//    DevExpress.XtraGrid.Views.Grid.GridView gv = this.MainView as DevExpress.XtraGrid.Views.Grid.GridView;
		//    gv.CollapseAllGroups();
		//}

		//public void Collapse(int rowHandle)
		//{
		//    DevExpress.XtraGrid.Views.Grid.GridView gv = this.MainView as DevExpress.XtraGrid.Views.Grid.GridView;
		//    if (rowHandle != Int32.MinValue)
		//        gv.CollapseGroupRow(rowHandle);
		//}

		#endregion

		#endregion

        #region Private methods

		private void InitStartValue()
		{
			totalCount = 0;
			totalSum = 0;
		}

        #endregion

		#region Internal methods

		//internal bool IsSharedRoster(string name)
		//{
		//    DirectoryContactsDataset dcs = this.DirectoryService.Contacts.DataSet as DirectoryContactsDataset;

		//    Verety.SharedMeta.DirectoryServiceMeta.Contacts.DirectoryContactsDataset.GroupsRow gr = dcs.Groups.FindByGroupName(name);

		//    if (gr != null)
		//    {
		//        return gr.Shared;
		//    }
		//    else
		//    {
		//        return false;
		//    }
		//}

		internal void UnSubScribeFromEvents()
		{
			this.MouseDown -= new MouseEventHandler(RosterGrid_MouseDown);
			this.MouseMove -= new MouseEventHandler(RosterGrid_MouseMove);
			this.DragOver -= new DragEventHandler(RosterGrid_DragOver);
			this.DragDrop -= new DragEventHandler(RosterGrid_DragDrop);

			if (this.MainView != null)
			{
				this.MainView.CustomSummaryCalculate -= new CustomSummaryEventHandler(MainView_CustomSummaryCalculate);
				this.MainView.CustomDrawCell -= new DevExpress.XtraGrid.Views.Base.RowCellCustomDrawEventHandler(MainView_CustomDrawCell);
				this.MainView.CustomRowFilter -= new RowFilterEventHandler(MainView_CustomRowFilter);
				this.MainView.GroupRowCollapsed -= new RowEventHandler(MainView_GroupRowCollapsed);
				this.MainView.GroupRowExpanded -= new RowEventHandler(MainView_GroupRowExpanded);
				this.MainView.EndGrouping -= new EventHandler(MainView_EndGrouping);
			}
		}

		internal void ExpandRows()
		{
			if (this.MainView != null)
			{
				foreach (int i in ExpandedRows)
				{
					if (i != Int32.MinValue)
					{
						this.MainView.ExpandGroupRow(i);
					}
				}
			}
		}

		#endregion

		#region Private delegates

		private delegate void SenderHandler(object sender);

		#endregion

		#region Persistency

		public void LoadPersistency(PersistencyDictionary state)
		{
			try
			{
				string value = state.GetString("GridLayout", string.Empty);
				if (value == string.Empty)
				{
					return;
				}
				List<byte> data = new List<byte>();
				for (int i = 0; i < value.Length; i++)
				{
					data.Add(Convert.ToByte(value[i]));
				}
				MemoryStream ms = new MemoryStream();
				ms.Write(data.ToArray(), 0, data.Count);
				ms.Seek(0, SeekOrigin.Begin);
				this.gridView1.RestoreLayoutFromStream(ms);
			}
			catch (Exception ex)
			{
				mParentModule.Host.LogManager.WriteError(this, "Cannot load layout: " + ex.Message, "RosterViewer");
			}
		}

		public void SavePersistency(PersistencyDictionary state)
		{
			try
			{
				MemoryStream ms = new MemoryStream();
				this.gridView1.SaveLayoutToStream(ms);
				ms.Seek(0, SeekOrigin.Begin);
				List<byte> data = new List<byte>();
				while (ms.CanRead)
				{
					int d = ms.ReadByte();
					if (d == -1)
					{
						break;
					}
					data.Add(Convert.ToByte(d));
				}
				string value = string.Empty;
				foreach (byte b in data)
				{
					value += Convert.ToChar(b);
				}

				state.SetString("GridLayout", value);
			}
			catch (Exception ex)
			{
				mParentModule.Host.LogManager.WriteError(this, "Cannot save layout: " + ex.Message, "RosterViewer");
			}
		}

		#endregion
	}
}
